package com.hk.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hk.auth.StpKit;
import com.hk.auth.service.SpaceUserAuthService;
import com.hk.enums.SpaceLevelEnum;
import com.hk.enums.SpaceRoleEnum;
import com.hk.enums.SpaceTypeEnum;
import com.hk.exception.ErrorCode;
import com.hk.exception.ThrowExceptionUtil;
import com.hk.mapper.SpaceMapper;
import com.hk.model.entity.Space;
import com.hk.model.entity.SpaceUser;
import com.hk.model.vo.IdVO;
import com.hk.model.vo.space.SpaceEditVO;
import com.hk.model.vo.space.SpaceOperateVO;
import com.hk.model.vo.space.SpaceQueryParamVO;
import com.hk.model.vo.space.SpaceVO;
import com.hk.model.vo.user.UserVO;
import com.hk.service.SpaceService;
import com.hk.service.SpaceUserService;
import com.hk.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author 20231
 * @description 针对表【space(空间)】的数据库操作Service实现
 * @createDate 2025-01-02 18:28:18
 */
@Service
@Slf4j
public class SpaceServiceImpl extends ServiceImpl<SpaceMapper, Space> implements SpaceService {

    @Resource
    private UserService userService;
    @Resource
    private HttpServletRequest request;
    @Resource
    private SpaceUserService spaceUserService;
    @Resource
    private SpaceUserAuthService spaceUserAuthService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(IdVO idVO) {
        Long spaceId = idVO.getId();
        spaceUserService.deleteBySpaceId(spaceId);
        this.removeById(spaceId);
    }

    @Override
    public SpaceVO updateSpace(SpaceOperateVO operateVO) {
        ThrowExceptionUtil.throwIf(operateVO == null || operateVO.getId() == null, ErrorCode.ERROR_SYSTEM);
        Long spaceId = operateVO.getId();
        Space space = this.getById(spaceId);
        ThrowExceptionUtil.throwIf(space == null, ErrorCode.ERROR_PARAM, "空间不存在");
        space.setSpaceName(operateVO.getSpaceName());
        boolean update = this.updateById(space);
        return converterVO(space);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SpaceVO addSpace(SpaceOperateVO operateVO) {
        ThrowExceptionUtil.throwIf(ObjectUtil.isNull(operateVO), ErrorCode.ERROR_SYSTEM);
        UserVO userVO = userService.getCurrentUser(request);
        Long userId = userVO.getId();

        String spaceName = operateVO.getSpaceName();
        Integer spaceType = operateVO.getSpaceType();
        SpaceTypeEnum spaceTypeEnum = SpaceTypeEnum.getEnumByValue(spaceType);
        if (spaceTypeEnum == null) {
            spaceTypeEnum = SpaceTypeEnum.PRIVATE;
        }
        if (StrUtil.isBlank(spaceName)) {
            spaceName = userVO.getUserName() + "的" + spaceTypeEnum.getText() + "空间";
        }
        //每个用户只能有一个空间
        Space space = new Space();
        space.setSpaceName(spaceName);
        space.setUserId(userId);
        space.setSpaceType(spaceTypeEnum.getValue());
        space.setSpaceLevel(SpaceLevelEnum.COMMON.getValue());
        space.setMaxSize(SpaceLevelEnum.COMMON.getMaxSize());
        space.setMaxCount(SpaceLevelEnum.COMMON.getMaxCount());
        String lock = String.valueOf(userId).intern();
        synchronized (lock) {
            boolean exists = this.lambdaQuery()
                    .eq(Space::getUserId, userId)
                    .eq(Space::getSpaceType, spaceType)
                    .exists();
            ThrowExceptionUtil.throwIf(exists, ErrorCode.ERROR_SYSTEM, "每个用户只能创建一个" + spaceTypeEnum.getText() + "空间");


            boolean save = this.save(space);
            //如果添加的是团队空间则需要将当前用户加入关联表中
            if (save && spaceTypeEnum.getValue() == SpaceTypeEnum.TEAM.getValue()) {
                SpaceUser spaceUser = new SpaceUser();
                spaceUser.setSpaceId(space.getId());
                spaceUser.setUserId(userId);
                spaceUser.setSpaceRole(SpaceRoleEnum.ADMIN.getValue());
                spaceUserService.save(spaceUser);
            }
        }
        return converterVO(space);
    }

    @Override
    public SpaceVO getSpaceInfo(Long id) {
        Space space = this.getById(id);
        SpaceVO spaceVO = null;
        if (space != null) {
            spaceVO = converterVO(space);
            UserVO userVO = null;
            if (space.getSpaceType() == SpaceTypeEnum.PRIVATE.getValue()) {
                userVO = userService.getUserInfo(space.getUserId());
                spaceVO.setUserVO(userVO);
            } else {
                Long loginId = Long.valueOf((String) StpKit.SPACE.getLoginId());
                userVO = userService.getUserInfo(loginId);
            }

            List<String> permissionList = spaceUserAuthService.getPermissionList(space, userVO);
            spaceVO.setPermissionList(permissionList);
        }
        return spaceVO;
    }

    @Override
    public Page<SpaceVO> getSpacePageList(SpaceQueryParamVO queryParamVO) {
        LambdaQueryWrapper<Space> query = new LambdaQueryWrapper<>();
        query.like(StrUtil.isNotBlank(queryParamVO.getSpaceName()), Space::getSpaceName, queryParamVO.getSpaceName());
        query.eq(queryParamVO.getSpaceLevel() != null, Space::getSpaceLevel, queryParamVO.getSpaceLevel());
        query.eq(queryParamVO.getSpaceType() != null, Space::getSpaceType, queryParamVO.getSpaceType());
        Page<Space> spacePage = this.page(new Page<>(queryParamVO.getCurrent(), queryParamVO.getPageSize()), query);
        Page<SpaceVO> spacevopage = new Page<>(spacePage.getCurrent(), spacePage.getSize(), spacePage.getTotal());
        spacevopage.setRecords(converterVO(spacePage.getRecords()));
        return spacevopage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SpaceVO editSpace(SpaceEditVO spaceEditVO) {
        ThrowExceptionUtil.throwIf(spaceEditVO == null, ErrorCode.ERROR_PARAM);

        Integer spaceLevel = spaceEditVO.getSpaceLevel();
        String spaceName = spaceEditVO.getSpaceName();
        Long maxCount = spaceEditVO.getMaxCount();
        Long maxSize = spaceEditVO.getMaxSize();
        Integer spaceType = spaceEditVO.getSpaceType();
        SpaceLevelEnum levelEnum = SpaceLevelEnum.getEnumByValue(spaceLevel);
        if (levelEnum == null) {
            levelEnum = SpaceLevelEnum.COMMON;
        }
        maxCount = maxCount == null ? levelEnum.getMaxCount() : maxCount;
        maxSize = maxSize == null ? levelEnum.getMaxSize() : maxSize * 1024 * 1024;

        Space newSpace = new Space();
        newSpace.setSpaceName(spaceName);
        newSpace.setSpaceLevel(levelEnum.getValue());
        newSpace.setMaxCount(maxCount);
        newSpace.setMaxSize(maxSize);

        if (spaceEditVO.getId() != null) {
            Space space = this.getById(spaceEditVO.getId());
            ThrowExceptionUtil.throwIf(space == null, ErrorCode.ERROR_PARAM);
            newSpace.setId(space.getId());
            this.updateById(newSpace);
            return this.getSpaceInfo(space.getId());
        } else {
            UserVO userVO = userService.getCurrentUser(request);
            ThrowExceptionUtil.throwIf(userVO == null, ErrorCode.NOT_LOGIN);
            SpaceTypeEnum spaceTypeEnum = SpaceTypeEnum.getEnumByValue(spaceType);
            if (spaceTypeEnum == null) {
                spaceTypeEnum = SpaceTypeEnum.PRIVATE;
            }
            Long userId = userVO.getId();
            newSpace.setUserId(userId);
            newSpace.setSpaceType(spaceTypeEnum.getValue());
            String lock = String.valueOf(userId).intern();
            synchronized (lock) {
                boolean exists = this.lambdaQuery().eq(Space::getUserId, userId).eq(Space::getSpaceType, spaceType).exists();
                ThrowExceptionUtil.throwIf(exists, ErrorCode.ERROR_SYSTEM, "每个用户只能创建一个" + spaceTypeEnum.getText());
                boolean save = this.save(newSpace);
                //如果添加的是团队空间则需要将当前用户加入关联表中
                if (save && spaceTypeEnum.getValue() == SpaceTypeEnum.TEAM.getValue()) {
                    SpaceUser spaceUser = new SpaceUser();
                    spaceUser.setSpaceId(newSpace.getId());
                    spaceUser.setUserId(userId);
                    spaceUser.setSpaceRole(SpaceRoleEnum.ADMIN.getValue());
                    spaceUserService.save(spaceUser);
                }
                return this.getSpaceInfo(newSpace.getId());
            }
        }
    }

    @Override
    public SpaceVO selectSpaceByUser(Long userId) {
        Space space = this.lambdaQuery().eq(Space::getUserId, userId).eq(Space::getSpaceType, SpaceTypeEnum.PRIVATE.getValue()).one();
        return converterVO(space);
    }

    @Override
    public Map<Long, SpaceVO> selectListMao(List<Long> spaceIdList) {
        List<SpaceVO> spaceVOS = this.selectList(spaceIdList);
        if (CollectionUtil.isEmpty(spaceVOS)) return new HashMap<>(0);
        return spaceVOS.stream().collect(Collectors.toMap(SpaceVO::getId, Function.identity()));
    }

    @Override
    public List<SpaceVO> selectList(List<Long> spaceIdList) {
        if (CollectionUtil.isEmpty(spaceIdList)) {
            return new ArrayList<>();
        }
        List<Space> spaces = this.listByIds(spaceIdList);
        return converterVO(spaces);
    }

    private SpaceVO converterVO(Space space) {
        if (space == null) return null;
        SpaceVO spaceVO = new SpaceVO();
        BeanUtils.copyProperties(space, spaceVO);
        return spaceVO;
    }

    private List<SpaceVO> converterVO(List<Space> spaceList) {
        if (CollectionUtil.isEmpty(spaceList)) return new ArrayList<>();
        return spaceList.stream().map(this::converterVO).collect(Collectors.toList());
    }
}




